package com.netease.nie.facade;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.netease.nie.base.cache.redis.Redis;
import com.netease.nie.base.utils.CopyUtils;
import com.netease.nie.base.utils.JsonUtils;
import com.netease.nie.base.utils.PageUtils;
import com.netease.nie.common.CommonBusinessTools;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.constants.CommonConstants;
import com.netease.nie.constants.CustomGoodsConstants;
import com.netease.nie.constants.DisplayTypeConstants;
import com.netease.nie.dto.ExchangeGoodsInfoListDto;
import com.netease.nie.dto.RobGoodsInfoDto;
import com.netease.nie.dto.RobGoodsInfoPeriodDto;
import com.netease.nie.dto.TopicDetailDto;
import com.netease.nie.dto.TopicDetailDto.CustomGoodsDto;
import com.netease.nie.dto.TopicGoodsDto;
import com.netease.nie.dto.TopicSnapshotDto;
import com.netease.nie.model.TopicDto;
import com.netease.nie.service.ExchangeGoodsInfoService;
import com.netease.nie.service.RobGoodsInfoPeriodService;
import com.netease.nie.service.RobGoodsInfoService;
import com.netease.nie.service.TopicGoodsService;
import com.netease.nie.service.TopicService;

@Service
public class TopicFacadeImpl extends CommonBusinessTools implements TopicFacade {

	private static final int PAGE_SIZE = CommonConstants.PAGE_SIZE;
	private static final String TOPIC_LIST = "Topic_List";
	private static final String TOPIC_PREFIX = CachePrefixConstants.TopicPrefix.TOPIC_PREFIX;
	private static final String TOPIC_GOODS_LIST_PREFIX = CachePrefixConstants.TopicPrefix.TOPIC_GOODS_LIST_PREFIX;
	private static final String ROB_GOODS_INFO_SNAPSHOT_PREFIX = CachePrefixConstants.RobGoodsPrefix.ROB_GOODS_INFO_SNAPSHOT_PREFIX;
	private static final String EXCHANGE_GOODS_INFO_SNAPSHOT_PREFIX = CachePrefixConstants.GoodsPrefix.EXCHANGE_GOODS_INFO_SNAPSHOT_PREFIX;
	private static final String GOODS_STOCK_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_STOCK_PREFIX;
	private static final String ROB_GOODS_ID_DISPLAYPERIOD_PREFIX = CachePrefixConstants.RobGoodsPrefix.ROB_GOODS_ID_DISPLAYPERIOD_PREFIX;
	
	@Autowired
	private TopicService topicService;
	
	@Autowired
	private TopicGoodsService topicGoodsService;
	
	@Autowired
	private RobGoodsInfoService robGoodsInfoService;
	
	@Autowired
	private RobGoodsInfoPeriodService robGoodsInfoPeriodService;
	
	@Autowired
	private ExchangeGoodsInfoService exchangeGoodsInfoService;
	
	@Autowired
	private Redis redis;
	
	public List<TopicSnapshotDto> queryTopicSnapshotDtos(int page) {
		int pageStartIndex = PageUtils.getPageStartIndex(page);
		int pageEndIndex = PageUtils.getPageEndIndex(page);
		String key = TOPIC_LIST;
		boolean exists = redis.exists(key);
		List<TopicDto> topicDtoList = null;
		if (!exists) {
			topicDtoList = topicService.queryAllTopicDtos();
			if (topicDtoList != null && !topicDtoList.isEmpty())
				redis.rpush(key, topicDtoList);
		} else
			topicDtoList = redis.lrange(key, pageStartIndex, --pageEndIndex, TopicDto.class);
		
		if (topicDtoList != null && !topicDtoList.isEmpty()) {
			List<TopicSnapshotDto> topicSnapshotDtoList = new ArrayList<TopicSnapshotDto>();
			int topicDtoListSize = topicDtoList.size();
			TopicDto topicDto = null;
			TopicSnapshotDto topicSnapshotDto = null;
			for (int i = 0; i < topicDtoListSize; i++) {
				topicDto = topicDtoList.get(i);
				topicSnapshotDto = new TopicSnapshotDto();
				CopyUtils.copy(topicSnapshotDto, topicDto);
				topicSnapshotDtoList.add(topicSnapshotDto);
			}
			
			replaceTopicSnapshotDtoCoverUrl(topicSnapshotDtoList, DisplayTypeConstants.WAP.getCode());
			return topicSnapshotDtoList;
		}
		return Collections.emptyList();
	}

	public TopicDetailDto queryTopicDetailDtoByTopicId(int topicId) {
		TopicDetailDto topicDetailDto = new TopicDetailDto();
		String topicKey = TOPIC_PREFIX + topicId;
		boolean isExistsTopicKey = redis.exists(topicKey);
		TopicDto topicDto = null;
		if (!isExistsTopicKey)
			topicDto = topicService.queryTopicDtoByTopicId(topicId);
		else 
			topicDto = redis.get(topicKey, TopicDto.class);
		
		if (topicDto != null) {
			CopyUtils.copy(topicDetailDto, topicDto);
			String topicGoodsListKey = TOPIC_GOODS_LIST_PREFIX + topicDto.getId();
			boolean isExistsTopicGoodsListKey = redis.exists(topicGoodsListKey);
			List<TopicGoodsDto> topicGoodsDtoList = null;
			if (!isExistsTopicGoodsListKey) {
				topicGoodsDtoList = topicGoodsService.queryTopicGoodsDtosByTopicId(topicId);
				if (topicGoodsDtoList != null && !topicGoodsDtoList.isEmpty())
					redis.rpush(topicGoodsListKey, topicGoodsDtoList);
			} else
				topicGoodsDtoList = redis.lrange(topicGoodsListKey, 0, -1, TopicGoodsDto.class);
			
			Map<String, CustomGoodsDto> robTypeCustomGoodsDtoMap = generateRobTypeCustomGoodsDtoMap(topicGoodsDtoList);
			Map<String, CustomGoodsDto> exchangeTypeCustomGoodsDtoMap = generateExchangeTypeCustomGoodsDtoMap(topicGoodsDtoList);
			List<CustomGoodsDto> customGoodsDtoList = new ArrayList<>();
			generateCustomGoodsDtoList(customGoodsDtoList, topicGoodsDtoList, robTypeCustomGoodsDtoMap, exchangeTypeCustomGoodsDtoMap);
			replaceCustomGoodsDtoThumbnailUrl(customGoodsDtoList, DisplayTypeConstants.WAP.getCode());
			topicDetailDto.setCustomGoodsDtoList(customGoodsDtoList);
			generateTopicDetailDtoCoverUrl(topicDetailDto, topicDto, DisplayTypeConstants.WAP.getCode());
		}
		
		return topicDetailDto;
	}
	
	private void generateCustomGoodsDtoList(List<CustomGoodsDto> customGoodsDtoList, 
			List<TopicGoodsDto> topicGoodsDtoList, 
			Map<String, CustomGoodsDto> robTypeCustomGoodsDtoMap, 
			Map<String, CustomGoodsDto> exchangeTypeCustomGoodsDtoMap) {
		if (topicGoodsDtoList != null && !topicGoodsDtoList.isEmpty()) {
			CustomGoodsDto customGoodsDto = null;
			TopicGoodsDto topicGoodsDto = null;
			int topicGoodsDtoListSize = topicGoodsDtoList.size();
			String customGoodsCodeAndId;
			for (int i = 0; i < topicGoodsDtoListSize; i++) {
				topicGoodsDto = topicGoodsDtoList.get(i);
				int customGoodsCode = topicGoodsDto.getCustomGoodsCode();
				int customGoodsId = topicGoodsDto.getCustomGoodsId();
				customGoodsCodeAndId = customGoodsCode + "-" + customGoodsId;
				if (robTypeCustomGoodsDtoMap.containsKey(customGoodsCodeAndId))
					customGoodsDto = robTypeCustomGoodsDtoMap.get(customGoodsCodeAndId);
				else if (exchangeTypeCustomGoodsDtoMap.containsKey(customGoodsCodeAndId))
					customGoodsDto = exchangeTypeCustomGoodsDtoMap.get(customGoodsCodeAndId);
				if (customGoodsDto != null)
					customGoodsDtoList.add(customGoodsDto);
			}
		}
	}
	
	private Map<String, CustomGoodsDto> generateRobTypeCustomGoodsDtoMap(List<TopicGoodsDto> topicGoodsDtoList) {
		if (topicGoodsDtoList != null && !topicGoodsDtoList.isEmpty()) {
			Map<String, CustomGoodsDto> robTypeCustomGoodsDtoMap = new HashMap<>();
			int topicGoodsDtoListSize = topicGoodsDtoList.size();
			List<Integer> robGoodsInfoIdList = new ArrayList<>();
			TopicGoodsDto topicGoodsDto = null;
			CustomGoodsDto customGoodsDto = null;
			RobGoodsInfoDto robGoodsInfoDto = null;
			String[] robGoodsInfoKeys = {};
			String[] robGoodsIdDisplayPeriodKeys = {};
			for (int i = 0; i < topicGoodsDtoListSize; i++) {
				topicGoodsDto = topicGoodsDtoList.get(i);
				int customGoodsCode = topicGoodsDto.getCustomGoodsCode();
				int customGoodsId = topicGoodsDto.getCustomGoodsId();
				if (customGoodsCode == CustomGoodsConstants.ROB.getCode()) {
					robGoodsInfoIdList.add(customGoodsId);
					robGoodsInfoKeys = (String[]) ArrayUtils.add(robGoodsInfoKeys, ROB_GOODS_INFO_SNAPSHOT_PREFIX + customGoodsId);
					robGoodsIdDisplayPeriodKeys = (String[]) ArrayUtils.add(robGoodsIdDisplayPeriodKeys, ROB_GOODS_ID_DISPLAYPERIOD_PREFIX + customGoodsId);
				}
			}
			
			if (!robGoodsInfoIdList.isEmpty()) {
				List<RobGoodsInfoDto> robGoodsInfoDtoList = generateRobGoodsInfoListDtoList(robGoodsInfoIdList, robGoodsInfoKeys);
				Map<Integer, Integer> robGoodsDisplayPeriodMap = generateRobGoodsDisplayPeriodMap(robGoodsInfoIdList, robGoodsIdDisplayPeriodKeys);
				
				//设置夺宝商品
				int robGoodsInfoDtoListSize = robGoodsInfoDtoList.size();
				for (int i = 0; i < robGoodsInfoDtoListSize; i++) {
					robGoodsInfoDto = robGoodsInfoDtoList.get(i);
					customGoodsDto = new CustomGoodsDto();
					customGoodsDto.setGoodsId(robGoodsInfoDto.getGoodsId());
					customGoodsDto.setCustomGoodsCode(CustomGoodsConstants.ROB.getCode());
					customGoodsDto.setCustomGoodsId(robGoodsInfoDto.getId());
					customGoodsDto.setPrice(robGoodsInfoDto.getPrice());
					customGoodsDto.setTitle(robGoodsInfoDto.getTitle());
					customGoodsDto.setThumbnailWapUrl(robGoodsInfoDto.getThumbnailWapUrl());
					customGoodsDto.setThumbnailWebUrl(robGoodsInfoDto.getThumbnailWebUrl());
					if (robGoodsDisplayPeriodMap.containsKey(robGoodsInfoDto.getId()))
						customGoodsDto.setDisplayPeriod(robGoodsDisplayPeriodMap.get(robGoodsInfoDto.getId()));
					robTypeCustomGoodsDtoMap.put(CustomGoodsConstants.ROB.getCode() + "-" + robGoodsInfoDto.getId(), customGoodsDto);
				}
			}
			return robTypeCustomGoodsDtoMap;
		}
		return Collections.emptyMap();
	}
	
	private Map<Integer, Integer> generateRobGoodsDisplayPeriodMap(List<Integer> robGoodsIdList, String[] robGoodsIdDisplayPeriodKeys) {
		Map<Integer, Integer> robGoodsIdDisplayPeriodMapper = new HashMap<Integer, Integer>();
		
		if (robGoodsIdDisplayPeriodKeys.length > 0) {
			List<String> strList = redis.mget(robGoodsIdDisplayPeriodKeys);
			if (strList != null && !strList.isEmpty()) {
				int strListSize = strList.size();
				for (int i = 0; i < strListSize; i++) {
					int robGoodsId = Integer.valueOf(StringUtils.removeStart(robGoodsIdDisplayPeriodKeys[i], CachePrefixConstants.RobGoodsPrefix.ROB_GOODS_ID_DISPLAYPERIOD_PREFIX));
					robGoodsIdDisplayPeriodMapper.put(robGoodsId, Integer.valueOf(strList.get(i)));
				}
			} else {
				List<RobGoodsInfoPeriodDto> robGoodsInfoPeriodDtoList = robGoodsInfoPeriodService.queryMaxPeriodRobGoodsInfoPeriodDtosByRobGoodsIds(robGoodsIdList);
				if (robGoodsInfoPeriodDtoList != null && !robGoodsInfoPeriodDtoList.isEmpty()) {
					int robGoodsInfoPeriodDtoListSize = robGoodsInfoPeriodDtoList.size();
					RobGoodsInfoPeriodDto robGoodsInfoPeriodDto = null;
					String[] keysvalues = {};
					String key = null;
					String value = null;
					List<String> keyValueList = new ArrayList<>();
					for (int i = 0; i < robGoodsInfoPeriodDtoListSize; i++) {
						robGoodsInfoPeriodDto = robGoodsInfoPeriodDtoList.get(i);
						key = ROB_GOODS_ID_DISPLAYPERIOD_PREFIX + robGoodsInfoPeriodDto.getRobGoodsId();
						value = JsonUtils.obj2String(robGoodsInfoPeriodDto.getDisplayPeriod());
						keyValueList.add(key);
						keyValueList.add(value);
						robGoodsIdDisplayPeriodMapper.put(robGoodsInfoPeriodDto.getRobGoodsId(), robGoodsInfoPeriodDto.getDisplayPeriod());
					}
					keysvalues = keyValueList.toArray(keysvalues);
					redis.mset(keysvalues);
				}
			}
		}
		return robGoodsIdDisplayPeriodMapper;
	}
	
	private Map<String, CustomGoodsDto> generateExchangeTypeCustomGoodsDtoMap(List<TopicGoodsDto> topicGoodsDtoList) {
		if (topicGoodsDtoList != null && !topicGoodsDtoList.isEmpty()) {
			Map<String, CustomGoodsDto> exchangeTypeCustomGoodsDtoMap = new HashMap<>();
			int topicGoodsDtoListSize = topicGoodsDtoList.size();
			List<Integer> exchangeGoodsInfoIdList = new ArrayList<>();
			TopicGoodsDto topicGoodsDto = null;
			CustomGoodsDto customGoodsDto = null;
			ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
			String[] exchangeGoodsInfoKeys = {};
			String[] exchangeGoodsStockKeys = {};
			for (int i = 0; i < topicGoodsDtoListSize; i++) {
				topicGoodsDto = topicGoodsDtoList.get(i);
				int customGoodsCode = topicGoodsDto.getCustomGoodsCode();
				int customGoodsId = topicGoodsDto.getCustomGoodsId();
				if (customGoodsCode == CustomGoodsConstants.EXCHANGE.getCode()) {
					exchangeGoodsInfoIdList.add(customGoodsId);
					exchangeGoodsInfoKeys = (String[]) ArrayUtils.add(exchangeGoodsInfoKeys, EXCHANGE_GOODS_INFO_SNAPSHOT_PREFIX + customGoodsId);
					exchangeGoodsStockKeys = (String[]) ArrayUtils.add(exchangeGoodsStockKeys, GOODS_STOCK_PREFIX + customGoodsId);
				}
			}
			
			if (!exchangeGoodsInfoIdList.isEmpty()) {
				List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList = generateExchangeGoodsInfoListDtoList(exchangeGoodsInfoIdList, exchangeGoodsInfoKeys);
				Map<Integer, Integer> exchangeGoodsStockMap = generateExchangeGoodsStockMap(exchangeGoodsStockKeys);
				
				//设置兑换商品
				int exchangeGoodsInfoDtoListSize = exchangeGoodsInfoListDtoList.size();
				for (int i = 0; i < exchangeGoodsInfoDtoListSize; i++) {
					exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
					customGoodsDto = new CustomGoodsDto();
					customGoodsDto.setCustomGoodsCode(CustomGoodsConstants.EXCHANGE.getCode());
					customGoodsDto.setCustomGoodsId(exchangeGoodsInfoListDto.getId());
					customGoodsDto.setPrice(exchangeGoodsInfoListDto.getPrice());
					customGoodsDto.setTitle(exchangeGoodsInfoListDto.getTitle());
					customGoodsDto.setThumbnailWapUrl(exchangeGoodsInfoListDto.getThumbnailWapUrl());
					customGoodsDto.setThumbnailWebUrl(exchangeGoodsInfoListDto.getThumbnailWebUrl());
					if (exchangeGoodsStockMap.containsKey(exchangeGoodsInfoListDto.getId()))
						customGoodsDto.setStock(exchangeGoodsStockMap.get(exchangeGoodsInfoListDto.getId()));
					exchangeTypeCustomGoodsDtoMap.put(CustomGoodsConstants.EXCHANGE.getCode() + "-" + exchangeGoodsInfoListDto.getId(), customGoodsDto);
				}
			}
			return exchangeTypeCustomGoodsDtoMap;
		}
		return Collections.emptyMap();
	}
	
	private Map<Integer, Integer> generateExchangeGoodsStockMap(String[] exchangeGoodsStockKeys) {
		if (exchangeGoodsStockKeys.length > 0) {
			List<String> strList = redis.mget(exchangeGoodsStockKeys);
			Map<Integer, Integer> exchangeGoodsStockMap = distillGoodsStock(
					exchangeGoodsStockKeys, strList);
			return exchangeGoodsStockMap;
		}
		return Collections.emptyMap();
	}
	
	private List<RobGoodsInfoDto> generateRobGoodsInfoListDtoList(List<Integer> robGoodsInfoIdList, String[] robGoodsInfoKeys) {
		List<String> strList = redis.mget(robGoodsInfoKeys);
		List<RobGoodsInfoDto> tempRobGoodsInfoDtoList = null, robGoodsInfoDtoList = null;
		RobGoodsInfoDto robGoodsInfoDto = null;
		List<Integer> needRefreshRobGoodsIdList = new ArrayList<>();
		String text = null;
		if (strList != null && !strList.isEmpty()) {
			robGoodsInfoDtoList = new ArrayList<>();
			int strListSize = strList.size();
			for (int i = 0; i < strListSize; i++) {
				text = strList.get(i);
				if (StringUtils.isBlank(text)) {
					int robGoodsId = Integer.valueOf(StringUtils.removeStart(robGoodsInfoKeys[i], CachePrefixConstants.RobGoodsPrefix.ROB_GOODS_INFO_SNAPSHOT_PREFIX));
					needRefreshRobGoodsIdList.add(robGoodsId);
					continue;
				}
				robGoodsInfoDto = JsonUtils.getClazz(text, RobGoodsInfoDto.class);
				robGoodsInfoDtoList.add(robGoodsInfoDto);
			}
			if (!needRefreshRobGoodsIdList.isEmpty()) {
				tempRobGoodsInfoDtoList = robGoodsInfoService.queryRobGoodsInfoDtosByRobGoodsIds(robGoodsInfoIdList);
				refreshRobGoodsInfoDtoList(tempRobGoodsInfoDtoList);
				robGoodsInfoDtoList.addAll(tempRobGoodsInfoDtoList);
			}
		} else {
			robGoodsInfoDtoList = robGoodsInfoService.queryRobGoodsInfoDtosByRobGoodsIds(robGoodsInfoIdList);
			refreshRobGoodsInfoDtoList(robGoodsInfoDtoList);
		}
		return robGoodsInfoDtoList;
	}
	
	private List<ExchangeGoodsInfoListDto> generateExchangeGoodsInfoListDtoList(List<Integer> exchangeGoodsInfoIdList, String[] exchangeGoodsInfoKeys) {
		List<String> strList = redis.mget(exchangeGoodsInfoKeys);
		List<ExchangeGoodsInfoListDto> tempExchangeGoodsInfoListDtoList = null, exchangeGoodsInfoListDtoList = null;
		ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
		List<Integer> needRefreshExchangeGoodsIdList = new ArrayList<>();
		String text = null;
		if (strList != null && !strList.isEmpty()) {
			int strListSize = strList.size();
			exchangeGoodsInfoListDtoList = new ArrayList<>();
			for (int i = 0; i < strListSize; i++) {
				text = strList.get(i);
				if (StringUtils.isBlank(text)) {
					int exchangeGoodsId = Integer.valueOf(StringUtils.removeStart(exchangeGoodsInfoKeys[i], CachePrefixConstants.GoodsPrefix.EXCHANGE_GOODS_INFO_SNAPSHOT_PREFIX));
					needRefreshExchangeGoodsIdList.add(exchangeGoodsId);
					continue;
				}
				exchangeGoodsInfoListDto = JsonUtils.getClazz(text, ExchangeGoodsInfoListDto.class);
				exchangeGoodsInfoListDtoList.add(exchangeGoodsInfoListDto);
			}
			if (!needRefreshExchangeGoodsIdList.isEmpty()) {
				tempExchangeGoodsInfoListDtoList = exchangeGoodsInfoService.queryExchangeGoodsInfoListDtosByIds(exchangeGoodsInfoIdList);
				refreshExchangeGoodsInfoListDtoList(tempExchangeGoodsInfoListDtoList);
			}
		} else {
			exchangeGoodsInfoListDtoList = exchangeGoodsInfoService.queryExchangeGoodsInfoListDtosByIds(exchangeGoodsInfoIdList);
			refreshExchangeGoodsInfoListDtoList(exchangeGoodsInfoListDtoList);
		}
		return exchangeGoodsInfoListDtoList;
	}
	
	private void refreshRobGoodsInfoDtoList(List<RobGoodsInfoDto> robGoodsInfoDtoList) {
		if (robGoodsInfoDtoList != null && !robGoodsInfoDtoList.isEmpty()) {
			int robGoodsInfoDtoListSize = robGoodsInfoDtoList.size();
			RobGoodsInfoDto robGoodsInfoDto = null;
			String key = null;
			String value = null;
			String[] keysvalues = {};
			List<String> keyValueList = new ArrayList<>();
			for (int i = 0; i < robGoodsInfoDtoListSize; i++) {
				robGoodsInfoDto = robGoodsInfoDtoList.get(i);
				key = ROB_GOODS_INFO_SNAPSHOT_PREFIX + robGoodsInfoDto.getId();
				value = JsonUtils.obj2String(robGoodsInfoDto);
				keyValueList.add(key);
				keyValueList.add(value);
			}
			keysvalues = keyValueList.toArray(keysvalues);
			redis.mset(keysvalues);
		}
	}
	
	private void refreshExchangeGoodsInfoListDtoList(List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList) {
		if (exchangeGoodsInfoListDtoList != null && !exchangeGoodsInfoListDtoList.isEmpty()) {
			int exchangeGoodsInfoListDtoListSize = exchangeGoodsInfoListDtoList.size();
			ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
			String key = null;
			String value = null;
			String[] keysvalues = {};
			List<String> keyValueList = new ArrayList<>();
			for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
				exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
				key = EXCHANGE_GOODS_INFO_SNAPSHOT_PREFIX + exchangeGoodsInfoListDto.getId();
				value = JsonUtils.obj2String(exchangeGoodsInfoListDto);
				keyValueList.add(key);
				keyValueList.add(value);
			}
			keysvalues = keyValueList.toArray(keysvalues);
			redis.mset(keysvalues);
		}
	}

}
